
package com.zzyl.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.zzyl.config.JsapiPayParam;
import com.zzyl.config.WeChatProperties;
import com.zzyl.constant.SuperConstant;
import com.zzyl.constant.TradingConstant;
import com.zzyl.entity.RefundRecord;
import com.zzyl.entity.Trading;
import com.zzyl.enums.BasicEnum;
import com.zzyl.enums.TradingStateEnum;
import com.zzyl.exception.BaseException;
import com.zzyl.mapper.TradingMapper;
import com.zzyl.service.RefundRecordService;
import com.zzyl.service.TradingService;
import com.zzyl.utils.ObjectUtil;
import com.zzyl.utils.WeChatPayUtil;
import com.zzyl.vo.TradingVo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.List;

/**
 * 交易订单表 服务实现类
 */
@Slf4j
@Service
public class TradingServiceImpl implements TradingService {

    @Autowired
    private TradingMapper tradingMapper;
    @Autowired
    private WeChatPayUtil weChatPayUtil;

    @Autowired
    private WeChatProperties weChatProperties;
    @Autowired
    private RefundRecordService refundRecordService;

    /**
     * 根据交易订单号查询交易信息
     */
    @Override
    public Trading findTradByTradingOrderNo(Long tradingOrderNo) {
        return tradingMapper.selectByTradingOrderNo(tradingOrderNo);
    }

    /**
     * 根据商品订单号查询交易信息
     */
    @Override
    public Trading findTradByProductOrderNo(Long productOrderNo, String tradingType) {
        return tradingMapper.selectByProductOrderNo(productOrderNo, tradingType);
    }

    /**
     * 根据交易状态查询交易列表
     */
    @Override
    public List<Trading> findListByTradingState(TradingStateEnum tradingState, Integer count) {
        count = NumberUtil.max(count, 10);
        return tradingMapper.selectListByTradingState(tradingState.getCode(), count);
    }

    /**
     * 新增或修改交易信息
     */
    @Override
    public Boolean saveOrUpdate(Trading trading) {
        if (trading.getId() == null) {
            return tradingMapper.insert(trading) > 0;
        } else {
            return tradingMapper.updateByPrimaryKey(trading) > 0;
        }
    }

    /**
     * 创建交易单
     *
     * @param trading 交易单信息
     * @return 交易单
     */
    @Override
    public TradingVo createTrading(Trading trading) {
        String jsonStr = weChatPayUtil.jsapi(trading.getTradingOrderNo().toString(), trading.getTradingAmount(), trading.getMemo(), trading.getOpenId());
        JSONObject payJsonObject = JSON.parseObject(jsonStr);
        String prepayId = payJsonObject.getString("prepay_id");
        if (ObjectUtil.isEmpty(payJsonObject) || ObjectUtil.isEmpty(prepayId)) {
            throw new BaseException(BasicEnum.APPLY_TRADE_FAIL);
        }

        //封装JSAPI调起支付的参数（给前端使用）
        Long timeStamp = System.currentTimeMillis() / 1000;
        String nonceStr = IdUtil.simpleUUID();
        String packages = "prepay_id=" + prepayId;

        String paySign = null;
        try {
            paySign = weChatPayUtil.createPaySign(timeStamp, nonceStr, packages);
        } catch (Exception e) {
            throw new BaseException(BasicEnum.GET_PAYMENT_SIGNATURE_FAIL);
        }

        JsapiPayParam jsapiPayParam = JsapiPayParam.builder()
                .timeStamp(timeStamp)
                .appId(weChatProperties.getAppId())
                .nonceStr(nonceStr)
                .packages(packages)
                .paySign(paySign)
                .build();

        //封装交易单各项参数
        trading.setIsRefund(SuperConstant.NO);
        trading.setEnterpriseId(Long.valueOf(weChatProperties.getMchId()));
        trading.setPlaceOrderCode(String.valueOf(BasicEnum.SUCCEED.getCode()));
        //设置jsapi调起支付的参数
        trading.setPlaceOrderJson(JSONUtil.toJsonStr(jsapiPayParam));
        trading.setTradingState(TradingConstant.TRADE_WAIT_BUYER_PAY_1);
        trading.setTradingChannel("小程序支付");
        this.saveOrUpdate(trading);

        return BeanUtil.toBean(trading, TradingVo.class);
    }

    /**
     * 关闭交易单
     *
     * @param tradingVo 交易单
     * @return 已关闭的交易单
     */
    @Override
    public TradingVo closeTrading(TradingVo tradingVo) {
        try {
            weChatPayUtil.closeTrading(tradingVo.getTradingOrderNo().toString());
        } catch (Exception e) {
            throw new BaseException(BasicEnum.CLOSE_TRADING_FAIL);
        }

        Trading trading = findTradByTradingOrderNo(tradingVo.getTradingOrderNo());
        trading.setTradingState(TradingConstant.TRADE_CLOSED_5);
        saveOrUpdate(trading);
        return BeanUtil.toBean(trading, TradingVo.class);
    }

    /**
     * 交易单退款
     *
     * @param tradingVo 交易单
     * @return 已退款交易单
     */
    @Override
    public TradingVo refundTrading(TradingVo tradingVo) {
        //1、生成退款请求编号
        tradingVo.setOutRequestNo(IdUtil.getSnowflakeNextId());
        Trading tradingHandler = findTradByTradingOrderNo(tradingVo.getTradingOrderNo());
        tradingVo.setTradingAmount(tradingHandler.getTradingAmount());
        tradingVo.setRefund(tradingHandler.getRefund());
        tradingVo.setOperTionRefund(tradingHandler.getTradingAmount());

        //调用微信退款
        String refundResult = weChatPayUtil.refund(
                tradingVo.getTradingOrderNo().toString(),
                tradingVo.getOutRequestNo().toString(),
                tradingVo.getOperTionRefund(),
                tradingVo.getTradingAmount());
        JSONObject refundJsonObject = JSON.parseObject(refundResult);

        //保存退款单信息
        RefundRecord refundRecord = RefundRecord.builder()
                .enterpriseId(tradingHandler.getEnterpriseId())
                .refundNo(tradingVo.getOutRequestNo())
                .refundAmount(tradingVo.getOperTionRefund())
                .productOrderNo(tradingHandler.getProductOrderNo())
                .tradingChannel(tradingHandler.getTradingChannel())
                .tradingOrderNo(tradingHandler.getTradingOrderNo())
                .memo(tradingVo.getTradingChannel())
                .build();
        refundRecord.setCreateTime(LocalDateTime.now());
        refundRecord.setRemark(tradingVo.getTradingChannel());
        refundRecord.setCreateType(tradingVo.getCreateType());
        switch (refundJsonObject.getString("status")) {
            //退款状态：0-未知错误 1-退款中，2-成功, 3-失败
            case TradingConstant.WECHAT_REFUND_SUCCESS:
                refundRecord.setRefundStatus(TradingConstant.REFUND_STATUS_SENDING_1);
                break;
            case TradingConstant.WECHAT_REFUND_CLOSED:
                refundRecord.setRefundStatus(TradingConstant.REFUND_STATUS_CLOSED_3);
                break;
            case TradingConstant.WECHAT_REFUND_PROCESSING:
                refundRecord.setRefundStatus(TradingConstant.REFUND_STATUS_SENDING_1);
                break;
            default:
                refundRecord.setRefundStatus(TradingConstant.REFUND_STATUS_FAIL_0);
                break;
        }
        refundRecordService.saveOrUpdate(refundRecord);

        return BeanUtil.toBean(tradingHandler, TradingVo.class);
    }

    /***
     *  统一收单线下交易查询
     * 该接口提供所有支付订单的查询，商户可以通过该接口主动查询订单状态，完成下一步的业务逻辑。
     * @param tradingVo 交易单
     * @return 交易单
     */
    @Override
    public TradingVo queryTrading(TradingVo tradingVo) {
        Trading tradingHandler = findTradByTradingOrderNo(tradingVo.getTradingOrderNo());
        String tradingJsonStr = weChatPayUtil.queryTrading(String.valueOf(tradingVo.getTradingOrderNo()));
        JSONObject tradingJsonObject = JSON.parseObject(tradingJsonStr);


        //交易单状态【1-待付款,2-付款中,3-付款失败,4-已结算,5-取消订单】
        switch (tradingJsonObject.getString("trade_state")) {
            case TradingConstant.WECHAT_TRADE_CLOSED:
                tradingHandler.setTradingState(TradingConstant.TRADE_CLOSED_5);
                break;
            case TradingConstant.WECHAT_TRADE_REVOKED:
                tradingHandler.setTradingState(TradingConstant.TRADE_CLOSED_5);
                break;
            case TradingConstant.WECHAT_TRADE_SUCCESS:
                tradingHandler.setTradingState(TradingConstant.TRADE_SUCCESS_4);
                break;
            case TradingConstant.WECHAT_TRADE_REFUND:
                tradingHandler.setTradingState(TradingConstant.TRADE_SUCCESS_4);
                break;
            default:
                log.error("查询交易单获得未知状态"+tradingJsonObject.getString("trade_state"));
                throw new BaseException(BasicEnum.UNKNOWN_TRADING_STATUS);
        }

        //修改交易单状态
        tradingHandler.setResultCode(tradingJsonObject.getString("trade_state"));
        tradingHandler.setResultJson(tradingJsonStr);
        saveOrUpdate(tradingHandler);
        return tradingVo;
    }
}


